iT邦幫忙

2022 iThome 鐵人賽

DAY 20
0
Mobile Development

Android studio 30天新手筆記系列 第 20

Day20-Android新手筆記-使用Room資料庫搭配Rxjava

  • 分享至 

  • xImage
  •  

Room提供更簡潔的方法將資料儲存於本機資料庫中,將SQL語法的INSERT、UPDATE、DELETE等指令包裝成註解,大大降低建立資料庫的時間,在使用上更加便利。

今天實作一個簡易的電話簿程式,使用到Rxjava與RecyclerView來協助撰寫,如果對RecyclerView較為不熟,可以往前看教學文章。

/images/emoticon/emoticon31.gif

今日目標:

XML布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:id="@+id/linearLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="120dp"
        android:orientation="horizontal"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <TextView
            android:id="@+id/textView2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="Name"
            android:textSize="20sp"/>

        <EditText
            android:id="@+id/edit_name"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="textPersonName" />
    </LinearLayout>

    <LinearLayout
        android:id="@+id/linearLayout2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:orientation="horizontal"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout">

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:gravity="center"
            android:text="Phone"
            android:textSize="20sp"/>

        <EditText
            android:id="@+id/edit_phone"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:ems="10"
            android:inputType="textPersonName" />
    </LinearLayout>

    <Button
        android:id="@+id/button_insert"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="50dp"
        android:layout_marginTop="50dp"
        android:text="新增"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />

    <Button
        android:id="@+id/button_delete"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="50dp"
        android:layout_marginEnd="50dp"
        android:text="刪除"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/linearLayout2" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerview"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginTop="20dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button_insert" />
</androidx.constraintlayout.widget.ConstraintLayout>

Java程式碼

Room由三層架構組合而成:

  • Entity
    使用@Entity標註此類別為表格物件。
//設定表格名稱
@Entity(tableName = "UserTable")
public class UserData {

    //設置自動累加id
    @PrimaryKey(autoGenerate = true)
    private int id;

    private String name;
    private String phone;

    public UserData(String name, String phone) {
        this.name = name;
        this.phone = phone;
    }

    //建立getter and setter方法
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }
}

@Entity標註後方須給表格名稱,使用@PrimaryKey標註則表示此變數會自動補上最新的數值,主要用於區分各筆資料。

  • Dao
    使用@Dao標註,這個類別主要放資料庫的一些方法
@androidx.room.Dao
public interface Dao {
    //資料表名稱
    String tableName = "UserTable";

    //新增資料的方法
    @Insert(onConflict = OnConflictStrategy.REPLACE)
    Completable insertData(UserData userData);

    //撈取資料的方法
    @Query("SELECT * FROM " + tableName)
    Maybe<List<UserData>> selectAllData();

    //刪除資料的方法
    @Query("DELETE  FROM "+tableName)
    Completable deleteAllData();
}

這層架構提供我們使用標註及少量的SQL語法操作資料庫,提升資料庫的建構效率。

  • DataBase
    使用@Database標註,綁定使用的表格與利用version設定當前版本。
@Database(entities = {UserData.class},version = 1,exportSchema = false)
public abstract class DataBase extends RoomDatabase {
    //資料庫名稱
    public static final String DB = "UserData.db";
    private static volatile DataBase instance;

    public static DataBase getInstance(Context context){
        //確認是否存在,避免重複消耗資源
        //fallbackToDestructiveMigration(),會直接把table重建
         if (instance==null){
             instance = Room.databaseBuilder(context,DataBase.class,DB)
                     .fallbackToDestructiveMigration()
                     .build();
         }
         return  instance;
    }

    abstract public Dao getDao();
}

以上三層建構好後,我們開始來撰寫我們的主程式:

MainActivity

public class MainActivity extends AppCompatActivity {

    RecyclerView recyclerView;
    RecyclerViewAdapter recyclerViewAdapter;
    Button button_insert, button_delete;
    EditText edit_name, edit_phone;
    UserData userData;
    List<UserData> userDataResponse = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //設置資料庫監視工具
        Stetho.initializeWithDefaults(this);

        button_insert = findViewById(R.id.button_insert);
        button_delete = findViewById(R.id.button_delete);
        edit_name = findViewById(R.id.edit_name);
        edit_phone = findViewById(R.id.edit_phone);
        recyclerView = findViewById(R.id.recyclerview);

        //設定 recyclerView 的 Adapter 和 Manager
        recyclerViewAdapter = new RecyclerViewAdapter();
        recyclerView.setAdapter(recyclerViewAdapter);
        //設置布局管理器
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
        //添加底線樣式
        recyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL));

        //onCreate時先抓取本機資料
        getRoomData();

        //新增按鈕點擊事件
        button_insert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                userData = new UserData(edit_name.getText().toString(), edit_phone.getText().toString());
                if(edit_name.getText().toString().matches("") != true && edit_phone.getText().toString().matches("") != true){
                    insertRoomData(userData);
                }
            }
        });

        //刪除按鈕點擊事件
        button_delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                deleteRoomData();
            }
        });

    }

    //新增資料
    public void insertRoomData(UserData userData) {
        DataBase.getInstance(MainActivity.this).getDao().insertData(userData)
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new CompletableObserver() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }
                    @Override
                    public void onComplete() {
                        //新增資料成功
                        //新增成功後清空輸入框
                        edit_name.setText("");
                        edit_phone.setText("");
                        //重新獲取資料
                        getRoomData();
                    }
                    @Override
                    public void onError(Throwable e) {
                        //新增資料失敗
                    }
                });
    }

    //刪除資料
    public void deleteRoomData() {
        DataBase.getInstance(MainActivity.this).getDao().deleteAllData()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new CompletableObserver() {
                    @Override
                    public void onSubscribe(Disposable d) {

                    }
                    @Override
                    public void onComplete() {
                        //刪除資料成功
                        //重新獲取資料
                        getRoomData();
                    }
                    @Override
                    public void onError(Throwable e) {
                        //刪除資料失敗
                    }
                });
    }

    //獲取資料
    public void getRoomData() {
        DataBase.getInstance(MainActivity.this).getDao().selectAllData()
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new MaybeObserver<List<UserData>>() {
                    @Override
                    public void onSubscribe(Disposable d) {
                    }
                    @Override
                    public void onSuccess(List<UserData> userDataList) {
                        //獲取資料成功
                        userDataResponse = userDataList;
                        //將userDataList傳入recyclerViewAdapter
                        recyclerViewAdapter.setRoomDataList(userDataList);
                        //刷新RecyclerView資料
                        recyclerViewAdapter.notifyDataSetChanged();
                    }
                    @Override
                    public void onError(Throwable e) {
                        //獲取資料失敗
                    }
                    @Override
                    public void onComplete() {
                    }
                });
    }
}

這邊附上RecyclerViewAdapter:

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {

    List<UserData>mDataList = new ArrayList<>();

    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView tv_Num,tv_Name,tv_Phone;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            tv_Num = itemView.findViewById(R.id.tv_Num);
            tv_Name = itemView.findViewById(R.id.tv_Name);
            tv_Phone = itemView.findViewById(R.id.tv_Phone);
        }
        void setShowData(int position){
            //設定顯示資料
            tv_Num.setText(String.valueOf(mDataList.get(position).getId()));
            tv_Name.setText(mDataList.get(position).getName());
            tv_Phone.setText(mDataList.get(position).getPhone());
        }
    }
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext())
                .inflate(R.layout.item,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        //設定顯示資料
        holder.setShowData(position);
    }

    @Override
    public int getItemCount() {
        return mDataList.size();
    }

    //傳入MainActivity中的userDataList
    public void setRoomDataList(List<UserData>userDataList){
        mDataList = userDataList;
        notifyDataSetChanged();
    }
}

Stetho資料庫監視工具

/images/emoticon/emoticon41.gif

手機執行畫面


上一篇
Day19-Android新手筆記-Retrofit使用與天氣API連線
下一篇
Day21-Android新手筆記-ScrollView 與 HorizontalScrollView 結合使用
系列文
Android studio 30天新手筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言